﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AppUtil;
using Vim25Api;
using System.Collections;

namespace VmwareSeacher
{
    public class VmwreIterator
    {
        protected AppUtil.AppUtil _appUtil = null;
        public AppUtil.AppUtil GetAppUtil
        {
            set { _appUtil = value; }
            get { return _appUtil; }

        }
        protected AppUtil.ServiceUtil _srvUtil = null;
        public AppUtil.ServiceUtil SrvUtil
        {
            set { _srvUtil = value; }
            get { return _srvUtil; }
        }
        protected AppUtil.VMUtils _vmUtils = null;

        protected VimService _service = null;
        protected ServiceContent _servicecontent = null;
        protected ManagedObjectReference _serviceRef = null;
        protected ManagedObjectReference _rootFolder = null;
        protected ManagedObjectReference _propCol = null;
        protected string serverIpstr;
        public string GetServerIp()
        {
            return serverIpstr;
        }

        public void init(string[] args)
        {
            _appUtil = AppUtil.AppUtil.initialize("VMwareSearcher"
                                            , VmwreIterator.constructOptions()
                                            , args);
            _srvUtil = _appUtil.getServiceUtil();
            _vmUtils = new VMUtils(_appUtil);

            try
            {
                _appUtil.connect();
                SvcConnection _svcConnection = _appUtil.getConnection();

                this._service = _svcConnection.Service;
                this._servicecontent = _svcConnection.ServiceContent;
                this._serviceRef = _svcConnection.ServiceRef;
                this._propCol = _svcConnection.PropCol;
                this._rootFolder = _svcConnection.ServiceContent.rootFolder;

                ValidateArgs();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                while (e.InnerException != null)
                {
                    //Console.WriteLine(e.InnerException);
                    e = e.InnerException;
                }
                throw e;
            }
            finally
            {
                //_appUtil.disConnect();
            }
        }

        public void uninit()
        {
            _appUtil.disConnect();
        }
        public int doSearch(IExecFilter filter)
        {
            RT_VALUE rt = RT_VALUE.STOP;
            rt = filter.onStart(this);
            if (rt == RT_VALUE.STOP)
            {
                return 0;
            }
            else if (rt == RT_VALUE.NEXT)
            {
                return 0;
            }
            try
            {
                //遍历数据中心
                ArrayList array_datacenters = _srvUtil.GetDecendentMoRefs(null, "Datacenter");
                foreach (object dc in array_datacenters)
                {
                    ManagedObjectReference datecenter = (ManagedObjectReference)((object[])dc)[0];
                    string datecenterName = (string)((object[])dc)[1];
                    Console.WriteLine(" found Datacenter: " + datecenterName + "  type:" + datecenter.type);

                    rt = filter.onDatacenter(datecenterName, datecenter);
                    if (rt == RT_VALUE.STOP)
                    {
                        return 0;
                    }
                    else if (rt == RT_VALUE.NEXT)
                    {
                        continue;
                    }

                    //遍历domain
                    ManagedObjectReference hostFolder = (ManagedObjectReference)_srvUtil.GetMoRefProp(datecenter, "hostFolder");
                    Object dc_childEntity = _srvUtil.GetDynamicProperty(hostFolder, "childEntity");
                    ManagedObjectReference[] domains = (ManagedObjectReference[])dc_childEntity;
                    foreach (object d in domains)
                    {
                        ManagedObjectReference domain = (ManagedObjectReference)d;
                        string domainsname = (string)_srvUtil.GetDynamicProperty(domain, "name");
                        Console.WriteLine(" found domain: " + domainsname + "  type:" + domain.type);

                        rt = filter.onDomain(domainsname, domain);
                        if (rt == RT_VALUE.STOP)
                        {
                            return 0;
                        }
                        else if (rt == RT_VALUE.NEXT)
                        {
                            continue;
                        }

                        //遍历主机
                        Object attr_hosts = _srvUtil.GetDynamicProperty(domain, "host");
                        ManagedObjectReference[] hosts = (ManagedObjectReference[])attr_hosts;
                        foreach (object h in hosts)
                        {
                            ManagedObjectReference host = (ManagedObjectReference)h;
                            string hostsname = (string)_srvUtil.GetDynamicProperty(host, "name");
                            Console.WriteLine(" found host: " + domainsname + " type:" + host.type);

                            rt = filter.onHost(hostsname, host);
                            if (rt == RT_VALUE.STOP)
                            {
                                return 0;
                            }
                            else if (rt == RT_VALUE.NEXT)
                            {
                                continue;
                            }
                            //遍历虚拟机
                            Object vms = _srvUtil.GetDynamicProperty(host, "vm");
                            foreach (object v in (ManagedObjectReference[])vms)
                            {
                                ManagedObjectReference vm = (ManagedObjectReference)v;
                                string vmname = (string)_srvUtil.GetDynamicProperty(vm, "name");
                                Console.WriteLine(" found host: " + vmname + " type:" + vm.type);

                                rt = filter.onVm(vmname, vm);
                                if (rt == RT_VALUE.STOP)
                                {
                                    return 0;
                                }
                                else if (rt == RT_VALUE.NEXT)
                                {
                                    continue;
                                }
                                //遍历设备
                                VirtualDevice[] devices = (VirtualDevice[])_srvUtil.GetDynamicProperty(vm, "config.hardware.device");
                                foreach (VirtualDevice device in devices)
                                {
                                    rt = filter.onDevice(device);
                                    if (rt == RT_VALUE.STOP)
                                    {
                                        return 0;
                                    }
                                    else if (rt == RT_VALUE.NEXT)
                                    {
                                        continue;
                                    }
                                }

                            }
                        }

                    }


                }
                return -1;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                filter.onException(e);
                while (e.InnerException != null)
                {
                    Console.WriteLine(e.InnerException);
                    filter.onException(e);
                    e = e.InnerException;
                }
                return -1;
            }
            finally
            {
                filter.onEnd(this);
            }
        }

        protected void ValidateArgs()
        {
            String apiType = _servicecontent.about.apiType;
            serverIpstr = _appUtil.get_option("url");
            //this.datacenter = _appUtil.get_option("dataCenter");
            //this.host = _appUtil.get_option("hostName");
            //this.portGroupName = _appUtil.get_option("portGroupName");
            //this.vswitchId = _appUtil.get_option("vSwitchId");
            //this.vlanId = _appUtil.get_option("vlanId");
            //this.checkVM = _appUtil.get_option("checkVM");

            //if (apiType.Equals("HostAgent"))
            //{
            //    if (host != null)
            //    {
            //        Console.WriteLine("Host should not be specified when running via Host");
            //        throw new ArgumentHandlingException("Host should not be Specified");
            //    }
            //    if (datacenter == null)
            //    {
            //        Console.WriteLine("Datacenter should be specified when running via Host");
            //        throw new ArgumentHandlingException("Datacenter not Specified");
            //    }
            //}
            //else if (apiType.Equals("VirtualCenter"))
            //{
            //    if ((datacenter == null) && (host == null))
            //    {
            //        Console.WriteLine("Atleast one from datacenter or host should be specified");
            //        throw new ArgumentHandlingException("Invalid Argument Specified");
            //    }
            //}

        }

        public void DumpHostPortGroup(HostPortGroup[] portGroups)
        {
            foreach (HostPortGroup portGroup in portGroups)
            {
                HostPortGroupSpec spec = portGroup.spec;
                Console.WriteLine("\t\tname : " + spec.name);
                Console.WriteLine("\t\tvswitchName : " + spec.vswitchName);
            }
        }

        public void BrowserObject(AppUtil.AppUtil _appUtil, String path)
        {
            AppUtil.ServiceUtil _srvUtil = _appUtil.getServiceUtil();
            try
            {
                ManagedObjectReference mor = _appUtil.getConnection().Service.FindByInventoryPath(_appUtil.getConnection().ServiceContent.searchIndex, path);
                if (mor != null)
                {
                    ShowMORInfo(mor);

                    if (mor.type.Equals("VirtualMachine"))
                    {
                        ObjectContent[] objContent = _srvUtil.GetObjectProperties(null, mor, new String[] { "name", "network", "summary.runtime.powerState", "guest.guestState", "runtime.connectionState", "config" });
                        DumpObjectContentList(objContent);
                    }
                    else if (mor.type.Equals("Datacenter"))
                    {
                        ObjectContent[] objContent = _srvUtil.GetObjectProperties(null, mor, new String[] { "name", "hostFolder", "network", "datastore" });
                        DumpObjectContentList(objContent);
                    }
                    else if (mor.type.Equals("Folder"))
                    {
                        ObjectContent[] objContent = _srvUtil.GetObjectProperties(null, mor, new String[] { "name", "childEntity" });
                        DumpObjectContentList(objContent);
                    }
                    else if (mor.type.Equals("ComputeResource"))
                    {
                        ObjectContent[] objContent = _srvUtil.GetObjectProperties(null, mor, new String[] { "name", "resourcePool", "network", "host", "datastore" });
                        DumpObjectContentList(objContent);
                    }
                    else if (mor.type.Equals("ResourcePool"))
                    {
                        ObjectContent[] objContent = _srvUtil.GetObjectProperties(null, mor, new String[] { "name", "resourcePool", "vm" });
                        DumpObjectContentList(objContent);
                    }
                }
                else
                {
                    Console.WriteLine("NotFound!");
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            //Console.WriteLine("");
        }

        public static OptionSpec[] constructOptions()
        {
            //OptionSpec[] useroptions = new OptionSpec[6];
            //useroptions[0] = new OptionSpec("vSwitchid", "String", 0
            //                               , "Name of the switch on which portgroup is to be modified"
            //                               , null);
            //useroptions[1] = new OptionSpec("hostName", "String", 0,
            //                                "Name of the host",
            //                                null);
            //useroptions[2] = new OptionSpec("portGroupName", "String", 1
            //                               , "Name of the portgroup"
            //                               , null);
            //useroptions[3] = new OptionSpec("dataCenter", "String", 0,
            //                                "Name of the datacenter",
            //                                null);
            //useroptions[4] = new OptionSpec("vlanId", "Integer", 1,
            //                                "new vlanId to set",
            //                                null);

            //useroptions[5] = new OptionSpec("checkVM", "String", 1,
            //                                "the name of VM which to check if power of of unConnected",
            //                                null);
            //return useroptions;
            return null;
        }

        void ShowMORInfo(ManagedObjectReference mor, string msg = null)
        {
            if (msg != null)
            {
                Console.WriteLine(msg);
            }
            Console.WriteLine("Object Type : " + mor.type);
            Console.WriteLine("Reference Value : " + mor.Value);
        }

        void DumpObjectContent(ObjectContent oc)
        {
            //ObjectContent oc = null;
            ManagedObjectReference mor = null;
            DynamicProperty[] pcary = null;
            DynamicProperty pc = null;

            mor = oc.obj;
            pcary = oc.propSet;

            Console.WriteLine("Object Type : " + mor.type);
            Console.WriteLine("Reference Value : " + mor.Value);

            if (pcary != null)
            {
                for (int pci = 0; pci < pcary.Length; pci++)
                {
                    pc = pcary[pci];
                    Console.WriteLine("\tProperty Name : " + pc.name);
                    if (pc != null)
                    {
                        if (!pc.val.GetType().IsArray)
                        {
                            Console.WriteLine("\tProperty Value : " + pc.val);
                            if (pc.val.GetType().Name.IndexOf("ManagedObjectReference") >= 0)
                            {
                                String fname = GetPropertiesName((ManagedObjectReference)pc.val);
                                Console.WriteLine("\tPropertiesName : " + fname);
                            }
                        }
                        else
                        {
                            Array ipcary = (Array)pc.val;
                            Console.WriteLine("\tVal : " + pc.val);
                            for (int ii = 0; ii < ipcary.Length; ii++)
                            {
                                Console.WriteLine("\t\t{0}.", ii);
                                object oval = ipcary.GetValue(ii);
                                if (oval.GetType().Name.IndexOf("ManagedObjectReference") >= 0)
                                {
                                    ManagedObjectReference imor = (ManagedObjectReference)oval;

                                    Console.WriteLine("\t\tInner Object Type : " + imor.type);
                                    Console.WriteLine("\t\tInner Reference Value : " + imor.Value);
                                    String fname = GetPropertiesName(imor);
                                    Console.WriteLine("\t\tPropertiesName : " + fname);
                                }
                                else
                                {
                                    Console.WriteLine("\t\tInner Property Value : " + oval);
                                }
                            }
                        }
                    }
                    Console.WriteLine("");
                }
            }
        }

        void DumpObjectContentList(ObjectContent[] ocary)
        {
            ObjectContent oc = null;
            for (int oci = 0; oci < ocary.Length; oci++)
            {
                oc = ocary[oci];
                DumpObjectContent(oc);
            }
        }

        String GetPropertiesName(ManagedObjectReference mor)
        {
            ObjectContent[] objContent = _srvUtil.GetObjectProperties(null, mor, new String[] { "name" });
            DynamicProperty dp = objContent[0].propSet[0];
            return (String)dp.val;
        }

        static void DumpMOR(ManagedObjectReference mor)
        {
            DynamicProperty[] pcary = null;
            DynamicProperty pc = null;


            Console.WriteLine("Object Type : " + mor.type);
            Console.WriteLine("Reference Value : " + mor.Value);
        }
    }

    public enum RT_VALUE
    {
        STOP,
        NEXT,
        CONTINUE,
    }
    public interface IExecFilter
    {
        
        RT_VALUE onDatacenter(string name, ManagedObjectReference datecenterMor);
        RT_VALUE onDomain(string name, ManagedObjectReference domainMor);
        RT_VALUE onHost(string name, ManagedObjectReference hostMor);
        RT_VALUE onStart(VmwreIterator vi);
        RT_VALUE onEnd(VmwreIterator vi);
        RT_VALUE onVm(string name, ManagedObjectReference vm);
        RT_VALUE onDevice(VirtualDevice device);
        void onException(Exception e);
    }   
}
